package com.dankegongyu.lib.common.widget;

import android.content.Context;
import android.content.res.TypedArray;
import androidx.annotation.IdRes;
import androidx.annotation.NonNull;
import android.text.Html;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.Animation;
import android.view.animation.Transformation;
import android.widget.RelativeLayout;
import android.widget.TextView;

import com.dankegongyu.lib.common.R;

/**
 * 展开折叠布局，
 * ！！注意： 它的父布局不能用ConstraintLayout，实际开发中发现设置了3行，4行的时候没有折叠
 *
 * @author wupuquan
 * @version 1.0
 * @since 2019/4/8 14:46
 */
public class DKExpandTextLayout extends RelativeLayout {

    private static final String TAG = DKExpandTextLayout.class.getSimpleName();

    // 折叠状态的行数
    private int mMaxCollapsedLines;
    @IdRes
    private int mTextViewId;
    @IdRes
    private int mToggleViewId;
    // 点TextView是否触发展开折叠
    private boolean mToggleOnTextClick;

    private TextView mTextView;
    private View mToggleView;

    private boolean mRelayout;
    private int mTextHeightWithMaxLines;
    private boolean mCollapsed = true;
    private int mMarginBetweenTextAndBottom;
    private int mCollapsedHeight;

    private int mAnimationDuration = 250;
    // 动画是否正在执行
    private boolean mAnimating;

    private OnExpandStateChangeListener mExpandStateChangeListener;

    public DKExpandTextLayout(Context context) {
        this(context, null);
    }

    public DKExpandTextLayout(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public DKExpandTextLayout(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);

        TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.DKExpandTextLayout);
        mMaxCollapsedLines = ta.getInt(R.styleable.DKExpandTextLayout_expand_collapsedLines, 3);
        mTextViewId = ta.getResourceId(R.styleable.DKExpandTextLayout_expand_textId, R.id.dk_expand_text);
        mToggleViewId = ta.getResourceId(R.styleable.DKExpandTextLayout_expand_toggleId, R.id.dk_expand_toggle);
        mToggleOnTextClick = ta.getBoolean(R.styleable.DKExpandTextLayout_expand_toggleOnTextClick, true);
        ta.recycle();
    }

    @Override
    protected void onFinishInflate() {
        super.onFinishInflate();
        findViews();
    }

    private void findViews() {
        mTextView = findViewById(mTextViewId);
        if (mToggleOnTextClick) {
            mTextView.setOnClickListener(mOnClickListener);
        }
        mToggleView = findViewById(mToggleViewId);
        mToggleView.setOnClickListener(mOnClickListener);
    }

    private OnClickListener mOnClickListener = new OnClickListener() {
        @Override
        public void onClick(View view) {
            if (mTextView.getLineCount() <= mMaxCollapsedLines) {
                return;
            }
            mCollapsed = !mCollapsed;
            mAnimating = true;

            Animation animation;
            if (mCollapsed) {
                animation = new ExpandCollapseAnimation(DKExpandTextLayout.this, getHeight(), mCollapsedHeight);
            } else {
                animation = new ExpandCollapseAnimation(DKExpandTextLayout.this, getHeight(), getHeight() +
                        mTextHeightWithMaxLines - mTextView.getHeight());
            }

            animation.setFillAfter(true);
            animation.setAnimationListener(new Animation.AnimationListener() {
                @Override
                public void onAnimationStart(Animation animation) {
                    if (!mCollapsed) {
                        mToggleView.setVisibility(View.GONE);
                    }
                }

                @Override
                public void onAnimationEnd(Animation animation) {
                    if (mCollapsed) {
                        mToggleView.setVisibility(View.VISIBLE);
                    }
                    // clear animation here to avoid repeated applyTransformation() calls
                    clearAnimation();
                    // clear the animation flag
                    mAnimating = false;

                    // notify the listener
                    if (mExpandStateChangeListener != null) {
                        mExpandStateChangeListener.onExpandStateChanged(mTextView, !mCollapsed);
                    }
                }

                @Override
                public void onAnimationRepeat(Animation animation) {
                }
            });

            clearAnimation();
            startAnimation(animation);
        }
    };

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        setMeasuredDimension(widthMeasureSpec, heightMeasureSpec);
        if (!mRelayout || getVisibility() == View.GONE) {
            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
            return;
        }
        mRelayout = false;

        mToggleView.setVisibility(View.GONE);
        mTextView.setMaxLines(Integer.MAX_VALUE);

        // measure
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);

        if (mTextView.getLineCount() <= mMaxCollapsedLines) {
            return;
        }

        mTextHeightWithMaxLines = getRealTextViewHeight(mTextView);

        if (mCollapsed) {
            mTextView.setMaxLines(mMaxCollapsedLines);
        }
        mToggleView.setVisibility(View.VISIBLE);

        // Re-measure
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);

        if (mCollapsed) {
            // Gets the margin between the TextView's bottom and the ViewGroup's bottom
            mTextView.post(new Runnable() {
                @Override
                public void run() {
                    mMarginBetweenTextAndBottom = getHeight() - mTextView.getHeight();
                }
            });
            // Saves the collapsed height of this ViewGroup
            mCollapsedHeight = getMeasuredHeight();
        }
    }

    private int getRealTextViewHeight(@NonNull TextView textView) {
        int textHeight = textView.getLayout().getLineTop(textView.getLineCount());
        int padding = textView.getCompoundPaddingTop() + textView.getCompoundPaddingBottom();
        return textHeight + padding;
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        // while an animation is in progress, intercept all the touch events to children to
        // prevent extra clicks during the animation
        return mAnimating;
    }

    public void setOnExpandStateChangeListener(OnExpandStateChangeListener listener) {
        mExpandStateChangeListener = listener;
    }

    public void setText(CharSequence text) {
        if (TextUtils.isEmpty(text)) {
            text = "";
        }
        mRelayout = true;
        mTextView.setText(Html.fromHtml(text.toString()));
        clearAnimation();
        getLayoutParams().height = ViewGroup.LayoutParams.WRAP_CONTENT;
        requestLayout();
    }

    class ExpandCollapseAnimation extends Animation {
        private final View mTargetView;
        private final int mStartHeight;
        private final int mEndHeight;

        public ExpandCollapseAnimation(View view, int startHeight, int endHeight) {
            mTargetView = view;
            mStartHeight = startHeight;
            mEndHeight = endHeight;
            setDuration(mAnimationDuration);
        }

        @Override
        protected void applyTransformation(float interpolatedTime, Transformation t) {
            final int newHeight = (int) ((mEndHeight - mStartHeight) * interpolatedTime + mStartHeight);
            mTextView.setMaxHeight(newHeight - mMarginBetweenTextAndBottom);
            mTargetView.getLayoutParams().height = newHeight;
            mTargetView.requestLayout();
        }

        @Override
        public void initialize(int width, int height, int parentWidth, int parentHeight) {
            super.initialize(width, height, parentWidth, parentHeight);
        }

        @Override
        public boolean willChangeBounds() {
            return true;
        }
    }

    public interface OnExpandStateChangeListener {
        /**
         * Called when the expand/collapse animation has been finished
         *
         * @param textView   - TextView being expanded/collapsed
         * @param isExpanded - true if the TextView has been expanded
         */
        void onExpandStateChanged(TextView textView, boolean isExpanded);
    }
}
